#ifndef __TCP_CLIENT_H__
#define __TCP_CLIENT_H__

#include "infra_types.h"
#include "infra_net.h"
#include "infra_timer.h"

/* State of TCP client */
typedef enum {
    TC_STATE_INVALID = 0,                          /* tcp client in invalid state */
    TC_STATE_INITIALIZED = 1,                      /* tcp client  in initializing state */
    TC_STATE_CONNECTED = 2,                        /* tcp client  in connected state */
    TC_STATE_DISCONNECTED = 3,                           /* tcp client  in disconnected state */
    TC_STATE_DISCONNECTED_RECONNECTING = 4,        /* tcp client  in reconnecting state */
    TC_STATE_CONNECT_BLOCK = 5                     /* tcp client  in connecting state when using async protocol stack */
} tc_state_t;


typedef struct Client tcp_client_t;


typedef void (*tc_state_notify_callback_fpt)(tcp_client_t *pclient, tc_state_t state);

typedef void (*tc_data_recv_callback_fpt)(tcp_client_t *pclient, 
                                        int packet_type, 
                                        uint8_t *payload, 
                                        uint32_t length, 
                                        void *user_data);


typedef struct Client {
    void                           *lock_generic;                               /* generic lock */
    uint32_t                        packet_id;                                  /* packet id */
    uint32_t                        send_data_timeout_ms;                       /* request timeout in millisecond */
    uint32_t                        cycle_timeout_ms;
    uint32_t                        buf_size_send;                              /* send buffer size in byte */
    uint32_t                        buf_size_send_max;                          /* send buffer size max limit in byte */
    uint32_t                        buf_size_read_max;                          /* recv buffer size max limit in byte */
    uint32_t                        buf_size_read;                              /* read buffer size in byte */
    //uint8_t                         keepalive_probes;                           /* keepalive probes */
    uint8_t                        *buf_send;                                   /* pointer of send buffer */
    uint8_t                        *buf_read;                                   /* pointer of read buffer */
    uint32_t                        buf_read_len;                              /* length of read buffer */
    utils_network_t                 ipstack;                                    /* network parameter */
    utils_time_t                    next_ping_time;                             /* next ping time */
    tc_state_t                      client_state;                               /* state of TCP client */
    
    utils_time_t                    reconnect_next_time;        /* the next time point of reconnect */
    uint32_t                        reconnect_time_interval_ms; /* time interval of this reconnect */
    uint32_t                        keepalive_interval_ms;                      /* keepalive interval in millisecond */
    
    void                           *lock_write_buf;                             /* lock of write */
    void                           *lock_read_buf;                              /* lock of read */
    //void                           *lock_yield;
    char                           *buf_host;

    tc_state_notify_callback_fpt     tc_state_notify_cb;          // tcp client state notify callback
    tc_data_recv_callback_fpt        tc_data_recv_cb;
    void                            *tc_data_recv_user_data;

} tcp_client_t, *tcp_client_pt;


tcp_client_t *tcp_client_new(const char *host, uint16_t port);
int tcp_client_connect(tcp_client_t *pclient);

int tcp_client_set_state_notify_cb(tcp_client_t *pclient, tc_state_notify_callback_fpt cb);
int tcp_client_set_data_recv_cb(tcp_client_t *pclient, tc_data_recv_callback_fpt cb, void *user_data);

void tcp_client_yield(tcp_client_t *pclient, int timeout_ms);
int tcp_client_send(tcp_client_t *pclient, unsigned char *buf, unsigned int buf_len);




#endif